from __future__ import annotations
from base import Observer
from abc import ABC, abstractmethod
from weather_data import WeatherData

class DisplayElement(ABC):
    @abstractmethod
    def display(self):
        ...


class CurrentConditionsDisplay(Observer, DisplayElement):
    def update(self, temp: float, humidity: float, pressure: float):
        self._temperature = temp
        self._humidity = humidity
        self.display()

    def display(self):
        print(f"Current conditions: {float(self._temperature)}F degrees and {float(self._humidity)}% humidity")

    def __init__(self, weather_data: WeatherData):
        self._weatherData: WeatherData = weather_data
        weather_data.register_observer(self)
        self._temperature: float = 0
        self._humidity: float = 0

class ForecastDisplay(Observer, DisplayElement):
    def update(self, temp: float, humidity: float, pressure: float):
        self._last_pressure = self._current_pressure
        self._current_pressure = pressure

        self.display()

    def display(self):
        print("Forecast:", end=' ')
        if self._current_pressure > self._last_pressure:
            print("Improving weather on the way!")
        elif self._current_pressure == self._last_pressure:
            print("More of the same")
        elif self._current_pressure < self._last_pressure:
            print("Watch out for cooler, rainy weather")

    def __init__(self, weather_data: WeatherData):
        self._weather_data = weather_data
        weather_data.register_observer(self)

        self._current_pressure: float = 29.92
        self._last_pressure: float = 0


class HeatIndexDisplay(Observer, DisplayElement):
    def update(self, temp: float, humidity: float, pressure: float):
        self._heatIndex = self.computeHeatIndex(temp, humidity)
        self.display()

    def display(self):
        print("Heat index is", float(self._heatIndex))

    def __init__(self, weather_data: WeatherData):
        self._weather_data = weather_data
        weather_data.register_observer(self)

        self._heatIndex: float = 0

    @staticmethod
    def computeHeatIndex(t: float, rh: float):
        index = ((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh) + (0.00941695 * (t * t))
                  + (0.00728898 * (rh * rh)) + (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh))
                  + (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 * (rh * rh * rh))
                  + (0.00000142721 * (t * t * t * rh)) + (0.000000197483 * (t * rh * rh * rh))
                  - (0.0000000218429 * (t * t * t * rh * rh)) + 0.000000000843296 * (t * t * rh * rh * rh))
                  - (0.0000000000481975 * (t * t * t * rh * rh * rh)))
        return index


class StatisticsDisplay(Observer, DisplayElement):
    def update(self, temp: float, humidity: float, pressure: float):
        self._temp_sum += temp
        self._num_readings += 1

        if temp > self._max_temp:
            self._max_temp = temp

        if temp < self._min_temp:
            self._min_temp = temp

        self.display()

    def display(self):
        print(f"Avg/Max/Min temperature = {self._temp_sum / self._num_readings}/{float(self._max_temp)}/{float(self._min_temp)}")

    def __init__(self, weather_data: WeatherData):
        self._weather_data = weather_data
        weather_data.register_observer(self)
        self._max_temp: float = 0
        self._min_temp: float = 200
        self._temp_sum: float = 0
        self._num_readings: int = 0
